package cn.iocoder.yudao.module.ems.controller.admin.equipment;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.ems.controller.admin.equipment.vo.EquipmentListReqVO;
import cn.iocoder.yudao.module.ems.controller.admin.equipment.vo.EquipmentSimpleRespVO;
import cn.iocoder.yudao.module.ems.controller.admin.spares.vo.SparesRespVO;
import cn.iocoder.yudao.module.ems.convert.equipment.EquipmentConvert;
import cn.iocoder.yudao.module.ems.convert.spares.SparesConvert;
import cn.iocoder.yudao.module.ems.dal.dataobject.eqtype.EqTypeDO;
import cn.iocoder.yudao.module.ems.dal.dataobject.equipment.EquipmentDO;
import cn.iocoder.yudao.module.ems.dal.dataobject.spares.SparesDO;
import cn.iocoder.yudao.module.ems.dal.dataobject.store.StoreDO;
import cn.iocoder.yudao.module.ems.dal.dataobject.supplier.SupplierDO;
import cn.iocoder.yudao.module.ems.service.eqtype.EqTypeService;
import cn.iocoder.yudao.module.ems.service.store.StoreService;
import cn.iocoder.yudao.module.ems.service.supplier.SupplierService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.annotations.*;

import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;

import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;

import cn.iocoder.yudao.module.ems.controller.admin.equipment.vo.*;
import cn.iocoder.yudao.module.ems.dal.dataobject.equipment.EquipmentDO;
import cn.iocoder.yudao.module.ems.convert.equipment.EquipmentConvert;
import cn.iocoder.yudao.module.ems.service.equipment.EquipmentService;

@Api(tags = "设备管理 - 设备台账")
@RestController
@RequestMapping("/ems/equipment")
@Validated
public class EquipmentController {

    @Resource
    private EquipmentService equipmentService;

    @Resource
    private SupplierService supplierService;

    @Resource
    private EqTypeService eqTypeService;

    @PostMapping("/create")
    @ApiOperation("创建设备")
    @PreAuthorize("@ss.hasPermission('ems:equipment:create')")
    public CommonResult<Long> createEquipment(@Valid @RequestBody EquipmentCreateReqVO createReqVO) {
        Long newEquipmentId = equipmentService.createEquipment(createReqVO);
        Set<Long> targetParentIds = createReqVO.getParentIds();
        Set<Long> targetSonIds = createReqVO.getSonIds();
        // 更新目标设备的子设备
        if (targetParentIds != null) {
            targetParentIds.forEach(id -> {
                EquipmentDO targetParent = equipmentService.getEquipment(id);
                Set<Long> rawIds = new HashSet<>();
                if (targetParent.getSonIds() != null) {
                    rawIds = targetParent.getSonIds();
                }
                rawIds.add(newEquipmentId);
                targetParent.setSonIds(rawIds);
                equipmentService.updateEquipment(targetParent);
            });
        }
        if (targetSonIds != null) {
            targetSonIds.forEach(id -> {
                EquipmentDO targetSon = equipmentService.getEquipment(id);
                Set<Long> rawIds = new HashSet<>();
                if (targetSon.getParentIds() != null) {
                    rawIds = targetSon.getParentIds();
                }
                rawIds.add(newEquipmentId);
                targetSon.setParentIds(rawIds);
                equipmentService.updateEquipment(targetSon);
            });
        }
        return success(newEquipmentId);
    }

    @PutMapping("/update")
    @ApiOperation("更新设备")
    @PreAuthorize("@ss.hasPermission('ems:equipment:update')")
    public CommonResult<Boolean> updateEquipment(@Valid @RequestBody EquipmentUpdateReqVO updateReqVO) {
        // 更新目标设备的子设备
        EquipmentDO raw = equipmentService.getEquipment(updateReqVO.getId());
        if (updateReqVO.getParentIds() != raw.getParentIds()) {
            Set<Long> different = new HashSet<>();
            if (updateReqVO.getParentIds() != null && raw.getParentIds() != null) {
                different.addAll(updateReqVO.getParentIds());
                different.removeAll(raw.getParentIds()); // 差集
            } else if (updateReqVO.getParentIds() != null) {
                different = updateReqVO.getParentIds();
            } else different = raw.getParentIds();
            different.forEach(id -> {
                if (updateReqVO.getParentIds().contains(id)) {
                    EquipmentDO targetParent = equipmentService.getEquipment(id);
                    Set<Long> rawIds = new HashSet<>();
                    if (targetParent.getSonIds() != null) {
                        rawIds = targetParent.getSonIds();
                    }
                    rawIds.add(updateReqVO.getId());
                    targetParent.setSonIds(rawIds);
                    equipmentService.updateEquipment(targetParent);
                } else {
                    EquipmentDO targetParent = equipmentService.getEquipment(id);
                    Set<Long> rawIds = new HashSet<>();
                    if (targetParent.getSonIds() != null) {
                        rawIds = targetParent.getSonIds();
                    }
                    rawIds.remove(updateReqVO.getId());
                    targetParent.setSonIds(rawIds);
                    equipmentService.updateEquipment(targetParent);
                }
            });
        }
        if (updateReqVO.getSonIds() != raw.getSonIds()) {
            Set<Long> different = new HashSet<>();
            if (updateReqVO.getSonIds() != null && raw.getSonIds() != null) {
                different.addAll(updateReqVO.getSonIds());
                different.removeAll(raw.getSonIds()); // 差集
            } else if (updateReqVO.getSonIds() != null) {
                different = updateReqVO.getSonIds();
            } else different = raw.getSonIds();
            different.forEach(id -> {
                if (updateReqVO.getSonIds().contains(id)) {
                    EquipmentDO targetSon = equipmentService.getEquipment(id);
                    Set<Long> rawIds = new HashSet<>();
                    if (targetSon.getParentIds() != null) {
                        rawIds = targetSon.getParentIds();
                    }
                    rawIds.add(updateReqVO.getId());
                    targetSon.setParentIds(rawIds);
                    equipmentService.updateEquipment(targetSon);
                } else {
                    EquipmentDO targetSon = equipmentService.getEquipment(id);
                    Set<Long> rawIds = new HashSet<>();
                    if (targetSon.getParentIds() != null) {
                        rawIds = targetSon.getParentIds();
                    }
                    rawIds.remove(updateReqVO.getId());
                    targetSon.setParentIds(rawIds);
                    equipmentService.updateEquipment(targetSon);
                }
            });
        }
        equipmentService.updateEquipment(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @ApiOperation("删除设备")
    @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
    @PreAuthorize("@ss.hasPermission('ems:equipment:delete')")
    public CommonResult<Boolean> deleteEquipment(@RequestParam("id") Long id) {
        equipmentService.deleteEquipment(id);
        return success(true);
    }

    @GetMapping("/get")
    @ApiOperation("获得设备")
    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
    @PreAuthorize("@ss.hasPermission('ems:equipment:query')")
    public CommonResult<EquipmentRespVO> getEquipment(@RequestParam("id") Long id) {
        EquipmentDO equipment = equipmentService.getEquipment(id);
        // 获得拼接需要的数据
        Long supplierId = equipment.getSupplierId();
        SupplierDO supplier = supplierService.getSupplier(supplierId);

        Long eqTypeId = equipment.getTypeId();
        EqTypeDO eqType = eqTypeService.getEqType(eqTypeId);

        Set<Long> parentIds = equipment.getParentIds();
        Set<Long> sonIds = equipment.getSonIds();
        Collection<EquipmentDO> parents = new ArrayList<>();
        Collection<EquipmentDO> sons = new ArrayList<>();
        if (parentIds != null) {
            parents = equipmentService.getEquipmentList(parentIds);
        }
        if (sonIds != null) {
            sons = equipmentService.getEquipmentList(sonIds);
        }

        // 拼接结果返回
        EquipmentRespVO respVO = EquipmentConvert.INSTANCE.convert(equipment);
        respVO.setSupplier(EquipmentConvert.INSTANCE.convert(supplier));
        respVO.setEqType(EquipmentConvert.INSTANCE.convert(eqType));
        respVO.setParents(EquipmentConvert.INSTANCE.convertCollection(parents));
        respVO.setSons(EquipmentConvert.INSTANCE.convertCollection(sons));
        return success(respVO);
    }

    @GetMapping("/list")
    @ApiOperation("获得设备列表")
    @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
    @PreAuthorize("@ss.hasPermission('ems:equipment:query')")
    public CommonResult<List<EquipmentRespVO>> getEquipmentList(@RequestParam("ids") Collection<Long> ids) {
        List<EquipmentDO> list = equipmentService.getEquipmentList(ids);
        return success(EquipmentConvert.INSTANCE.convertList(list));
    }

    @GetMapping("/page")
    @ApiOperation("获得设备分页")
    @PreAuthorize("@ss.hasPermission('ems:equipment:query')")
    public CommonResult<PageResult<EquipmentRespVO>> getEquipmentPage(@Valid EquipmentPageReqVO pageVO) {
        // 获得分页列表
        PageResult<EquipmentDO> pageResult = equipmentService.getEquipmentPage(pageVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return success(new PageResult<>(pageResult.getTotal())); // 返回空
        }
        // 获得拼接需要的数据
        Collection<Long> supplierIds = convertList(pageResult.getList(), EquipmentDO::getSupplierId);
        Map<Long, SupplierDO> supplierMap = supplierService.getSupplierMap(supplierIds);

        Collection<Long> eqTypeIds = convertList(pageResult.getList(), EquipmentDO::getTypeId);
        Map<Long, EqTypeDO> eqTypeMap = eqTypeService.getEqTypeMap(eqTypeIds);

        // 拼接结果返回
        List<EquipmentRespVO> equipmentList = new ArrayList<>(pageResult.getList().size());
        pageResult.getList().forEach(equipment -> {
            EquipmentRespVO respVO = EquipmentConvert.INSTANCE.convert(equipment);
            respVO.setSupplier(EquipmentConvert.INSTANCE.convert(supplierMap.get(equipment.getSupplierId())));
            respVO.setEqType(EquipmentConvert.INSTANCE.convert(eqTypeMap.get(equipment.getTypeId())));
            equipmentList.add(respVO);
        });
        return success(new PageResult<>(equipmentList, pageResult.getTotal()));
    }

    @GetMapping("/export-excel")
    @ApiOperation("导出设备 Excel")
    @PreAuthorize("@ss.hasPermission('ems:equipment:export')")
    @OperateLog(type = EXPORT)
    public void exportEquipmentExcel(@Valid EquipmentExportReqVO exportReqVO, HttpServletResponse response) throws IOException {
        List<EquipmentDO> list = equipmentService.getEquipmentList(exportReqVO);
        // 导出 Excel
        List<EquipmentExcelVO> datas = EquipmentConvert.INSTANCE.convertList02(list);
        ExcelUtils.write(response, "设备.xls", "数据", EquipmentExcelVO.class, datas);
    }

    @GetMapping("/list-all-simple")
    @ApiOperation(value = "获取设备精简信息列表", notes = "只包含被开启的分类，主要用于前端的下拉选项")
    public CommonResult<List<EquipmentSimpleRespVO>> getSimpleEquipments() {
        // 获得分类列表，只要开启状态的
        EquipmentListReqVO reqVO = new EquipmentListReqVO();
        List<EquipmentDO> list = equipmentService.getSimpleEquipments(reqVO);
        return success(EquipmentConvert.INSTANCE.convertList03(list));
    }

}
